package cn.sytton.taffecloud.common.excel;

import cn.sytton.taffecloud.common.base.util.JsonUtil;
import cn.sytton.taffecloud.common.excel.model.ExcelField;
import cn.sytton.taffecloud.common.excel.model.ExcelFormat;
import cn.sytton.taffecloud.common.excel.util.OutputStreamUtil;
import cn.sytton.taffecloud.common.excel.util.ServletUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFColor;

import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;

/**
 * Excel工具类
 *
 * @author skyrock
 */
@Slf4j
public class ExcelExport {
    /**
     * 工作薄对象
     */
    private Workbook wb;
    /**
     * 工作表对象
     */
    private Sheet sheet;
    /**
     * 导出字段
     */
    private List<ExcelField> fields;
    /**
     * 导出数据转换函数
     */
    private Map<String, Map<String, ExcelFormat>> format;
    /**
     * 数据
     */
    private List<?> data;

    /**
     * 对list数据源将其里面的数据导入到excel表单
     */
    public void exportExcel(String name, List<ExcelField> fields, List<?> data,  Map<String, Map<String, ExcelFormat>> format) {
        HttpServletResponse response = ServletUtil.getResponse();
        assert response != null;
        try {
            this.fields = fields;
            this.data = data;
            this.format = format;
            createWorkbook(name);
            writeSheet();
            OutputStreamUtil.setDownloadHeader(response, name, 0, false);
            wb.write(response.getOutputStream());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        finally {
            IOUtils.closeQuietly(wb);
        }
    }

    /**
     * 创建一个工作簿
     */
    private void createWorkbook(String sheetName) {
        wb = new SXSSFWorkbook(500);
        sheet = wb.createSheet();
        wb.setSheetName(0, sheetName);
    }

    /**
     * 创建写入数据到Sheet
     */
    private void writeSheet() {
        Row row = sheet.createRow(0);
        for(int i = 0; i < fields.size(); i++) {
            writeHeadCell(row, fields.get(i), i);
        }
        for (int i = 0; i < data.size(); i++) {
            row = sheet.createRow(1+i);
            writeDataRow(row, data.get(i));
        }
    }

    private void writeHeadCell(Row row, ExcelField field, int column) {
        row.setHeightInPoints(36);
        Cell cell = row.createCell(column);
        cell.setCellValue(field.getName());
        sheet.setColumnWidth(column, (int) ((16 + 0.72) * 256));
        cell.setCellStyle(getHeadStyle());
    }

    /**
     * 添加单元格
     */
    private void writeDataRow(Row row, Object data) {
        row.setHeightInPoints(26);
        for(int i = 0; i < fields.size(); i++) {
            Cell cell = row.createCell(i);
            Map<String, Object> mapData = JsonUtil.getEntity(JsonUtil.getString(data));
            Object value = mapData.get(fields.get(i).getField());
            cell.setCellValue(value == null ? "" : getFormatValue(fields.get(i).getField(), value.toString()));
            cell.setCellStyle(getDataStyle());
        }
    }

    private String getFormatValue(String field, String value) {
        if (format.containsKey(field)) {
            if (format.get(field).containsKey(value)) {
                return format.get(field).get(value).getText();
            }
            return value;
        }
        return value;
    }

    private CellStyle getDataStyle() {
        CellStyle style = wb.createCellStyle();
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setBorderRight(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderTop(BorderStyle.THIN);
        style.setBorderBottom(BorderStyle.THIN);
        return style;
    }

    private CellStyle getHeadStyle() {
        CellStyle style = getDataStyle();
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        style.setFillForegroundColor(new XSSFColor( new java.awt.Color(64, 158, 255), null));
        return style;
    }
}
